package com.zhijian.medical.service.impl;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.zhijian.medical.dao.local.SangerMapper;
import com.zhijian.medical.entity.dto.SangerCxPcrCwchSjDto;
import com.zhijian.medical.entity.dto.SangerSjfxDto;
import com.zhijian.medical.entity.dto.SangerSjpzqPcrDto;
import com.zhijian.medical.entity.dto.SangerSjpzqTxDto;
import com.zhijian.medical.entity.po.*;
import com.zhijian.medical.entity.vo.request.ExperimentProcessSampleSearchVo;
import com.zhijian.medical.entity.vo.request.SangerSaveOrUpdateVo;
import com.zhijian.medical.entity.vo.request.SangerSearchVo;
import com.zhijian.medical.entity.vo.response.ExperimentProcessSampleHstqVo;
import com.zhijian.medical.entity.vo.response.SangerVo;
import com.zhijian.medical.enums.ExperimentTypeEnum;
import com.zhijian.medical.enums.SangerSampleStatusEnum;
import com.zhijian.medical.enums.SangerStatusEnum;
import com.zhijian.medical.enums.StatusEnum;
import com.zhijian.medical.holder.CurrentUserHolder;
import com.zhijian.medical.service.*;
import com.zhijian.medical.util.AssertUtil;
import com.zhijian.medical.util.JsonUtil;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 一代测序主表业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-08-11 17:14:03
 */
@Slf4j
@Service
public class SangerServiceImpl implements SangerService {

    @Autowired
    private SangerMapper mapper;

    @Autowired
    private SangerSjpzqService sangerSjpzqService;

    @Autowired
    private ExperimentProcessSampleService experimentProcessSampleService;

    @Autowired
    private SangerHschyq1Service sangerHschyq1Service;

    @Autowired
    private SangerHschyq2Service sangerHschyq2Service;

    @Autowired
    private SangerHszbqService sangerHszbqService;

    @Autowired
    private SangerHskzyqService sangerHskzyqService;

    @Autowired
    private SangerCwfxyqService sangerCwfxyqService;

    @Autowired
    private SangerHskzeqService sangerHskzeqService;

    @Autowired
    private SangerHscheqService sangerHscheqService;

    @Autowired
    private SangerCxqService sangerCxqService;

    @Autowired
    private SangerSjfxService sangerSjfxService;

    @Autowired
    private ExperimentProcessSampleLogService experimentProcessSampleLogService;

    @Autowired
    private ExperimentProcessSampleHstqService experimentProcessSampleHstqService;

    /**
     * 编号
     */
    private static final String number = "FZ-SOP-010-01-%s-%s";

    @Override
    public Sanger selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public SangerVo selectVoById(Long id) {
        SangerVo sangerVo = mapper.selectVoById(id);
        if (Objects.isNull(sangerVo)) {
            return null;
        }
        sangerVo.setExperimentProcessSampleList(experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .experimentProcessId(id)
                .mainType(ExperimentTypeEnum.SANGER.getCode().byteValue())
                .build()));
        return sangerVo;
    }

    @Override
    public SangerVo selectVoBySangerId(Long sangerId) {
        return null;
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public Long insert(Sanger sanger) {
        Date now = new Date();
        sanger.setCreateTime(now);
        sanger.setUpdateTime(now);
        return mapper.insert(sanger) > 0 ? sanger.getId() : 0L;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public Long insert(SangerSaveOrUpdateVo sangerSaveOrUpdateVo) {
        Sanger sanger = new Sanger();
        BeanUtils.copyProperties(sangerSaveOrUpdateVo, sanger);
        sanger.setStatus(SangerStatusEnum.SJPZQ.getCode().byteValue());
        Date now = new Date();
        sanger.setStartTime(now);
        String today = DateUtil.formatDate(now);
        //今天有几个实验了
        Integer count = this.count(SangerSearchVo.builder()
                .startDay(today)
                .build());
        String processNumber = String.format(number, DateUtil.format(now, "yyyyMMdd"), String.format("%02d", count + 1));
        sanger.setProcessNumber(processNumber);
        //先保存主表
        Long sangerId = this.insert(sanger);
        //再保存其他数据
        saveOtherData(sangerId, sangerSaveOrUpdateVo.getName(), processNumber, sangerSaveOrUpdateVo.getSampleIds());
        return sangerId;
    }

    /**
     * 保存其他数据
     *
     * @param sangerId
     * @param sampleIds
     */
    private void saveOtherData(Long sangerId, String sangerName, String processNumber, List<Long> sampleIds) {
        //试剂配置区数据
        SangerSjpzq sangerSjpzq = new SangerSjpzq();

        //核酸纯化一区 （普通PCR产物纯化）
        SangerHschyq1 sangerHschyq1 = new SangerHschyq1();
        sangerHschyq1.setSangerId(sangerId);

        //样本数量*2
        int sampleDoubleSize = sampleIds.size() * 2;

        final int[] number = {1};
        List<SangerSjpzqPcrDto> sangerSjpzqPcrDtoList = Lists.newArrayList();

        //数据分析区数据
        List<SangerSjfxDto> sjfxDataList = Lists.newArrayList();

        //样本日志数据
        List<ExperimentProcessSampleLog> experimentProcessSampleLogList = Lists.newArrayList();

        //核酸提取记录id
        final Long[] hstqId = {null};
        sampleIds.forEach(s -> {
            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectById(s);
            AssertUtil.notNull(experimentProcessSample, "有样本不存在或者已被删除");
            hstqId[0] = experimentProcessSample.getHtstqId();
            //样本的监测项目
            String[] samplerProjects = experimentProcessSample.getProject().split(",");
            Arrays.stream(samplerProjects).forEach(s1 -> {
                SangerSjpzqPcrDto sangerSjpzqPcrFDto = new SangerSjpzqPcrDto();
                sangerSjpzqPcrFDto.setNumber(number[0]);
                sangerSjpzqPcrFDto.setFzblh(experimentProcessSample.getMoleculePathologyNumber());
                sangerSjpzqPcrFDto.setProject(s1);
                sangerSjpzqPcrFDto.setTurn("F");
                sangerSjpzqPcrDtoList.add(sangerSjpzqPcrFDto);
                number[0]++;

                SangerSjpzqPcrDto sangerSjpzqPcrRDto = new SangerSjpzqPcrDto();
                sangerSjpzqPcrRDto.setFzblh(experimentProcessSample.getMoleculePathologyNumber());
                sangerSjpzqPcrRDto.setNumber(number[0]);
                sangerSjpzqPcrRDto.setProject(s1);
                sangerSjpzqPcrRDto.setTurn("R");
                sangerSjpzqPcrDtoList.add(sangerSjpzqPcrRDto);
                number[0]++;

                sjfxDataList.add(SangerSjfxDto.builder()
                        .fzblh(experimentProcessSample.getMoleculePathologyNumber())
                        .project(s1)
                        .build());
            });

            experimentProcessSampleService.updateByPrimaryKeySelective(ExperimentProcessSample.builder()
                    .id(s)
                    .experimentProcessId(sangerId)
                    //状态改为检测中
                    .status(SangerSampleStatusEnum.JCZ.getCode().byteValue())
                    .build());

            experimentProcessSampleLogList.add(ExperimentProcessSampleLog.builder()
                    .sampleId(s)
                    .fishId(sangerId)
                    .mainType(experimentProcessSample.getMainType())
                    .op(String.format("%s%s-待检测", sangerName, processNumber))
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build());

        });

        //保存样本日志
        experimentProcessSampleLogService.saveBatch(experimentProcessSampleLogList);

        String s = JsonUtil.toString(sangerSjpzqPcrDtoList);
        sangerSjpzq.setPcrData(s);

        sangerHschyq1.setChcwfywzjbhData(s);

        List<SangerSjpzqTxDto> qtxckitDtoList = Lists.newArrayList();
        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("Q-solution")
                .tj(new BigDecimal("4.0"))
                .atj(new BigDecimal("4.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("10X Buffer")
                .tj(new BigDecimal("2.0"))
                .atj(new BigDecimal("2.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("dNTP mixture")
                .tj(new BigDecimal("2.0"))
                .atj(new BigDecimal("2.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("F(10μM)")
                .tj(new BigDecimal("0.5"))
                .atj(new BigDecimal("0.5").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("R(10μM)")
                .tj(new BigDecimal("0.5"))
                .atj(new BigDecimal("0.5").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("Taq(5u/μL)")
                .tj(new BigDecimal("0.25"))
                .atj(new BigDecimal("0.25").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("DNA(120ng)")
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("H2O")
                .tj(new BigDecimal("0.75"))
                .atj(new BigDecimal("0.75").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        qtxckitDtoList.add(SangerSjpzqTxDto.builder()
                .zf("总体积")
                .tj(new BigDecimal("20.0"))
                .atj(new BigDecimal("20.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        sangerSjpzq.setQtxckitData(JsonUtil.toString(qtxckitDtoList));
        sangerSjpzq.setQtxckit(StatusEnum.NORMAL.getCode().byteValue());

        List<SangerSjpzqTxDto> mg2DtoList = Lists.newArrayList();

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("10X Buffer")
                .tj(new BigDecimal("2.0"))
                .atj(new BigDecimal("2.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("dNTP mixture")
                .tj(new BigDecimal("2.0"))
                .atj(new BigDecimal("2.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("Mg2+")
                .tj(new BigDecimal("0.75"))
                .atj(new BigDecimal("0.75").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("F(10μM)")
                .tj(new BigDecimal("0.5"))
                .atj(new BigDecimal("0.5").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("R(10μM)")
                .tj(new BigDecimal("0.5"))
                .atj(new BigDecimal("0.5").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("Taq(5u/μL)")
                .tj(new BigDecimal("0.25"))
                .atj(new BigDecimal("0.25").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("DNA(120ng)")
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("H2O")
                .tj(new BigDecimal("4.0"))
                .atj(new BigDecimal("4.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        mg2DtoList.add(SangerSjpzqTxDto.builder()
                .zf("总体积")
                .tj(new BigDecimal("20.0"))
                .atj(new BigDecimal("20.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        sangerSjpzq.setMg2txpgdgfrData(JsonUtil.toString(mg2DtoList));
        sangerSjpzq.setMg2txpgdgfr(StatusEnum.NORMAL.getCode().byteValue());
        sangerSjpzq.setSangerId(sangerId);

        List<SangerSjpzqTxDto> hscwyq2Dtos = Lists.newArrayList();

        hscwyq2Dtos.add(SangerSjpzqTxDto.builder()
                .zf("5× Sequencing Buffer")
                .tj(new BigDecimal("3.75"))
                .atj(new BigDecimal("3.75").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        hscwyq2Dtos.add(SangerSjpzqTxDto.builder()
                .zf("2.5× BigDye")
                .tj(new BigDecimal("0.5"))
                .atj(new BigDecimal("0.5").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .build());

        hscwyq2Dtos.add(SangerSjpzqTxDto.builder()
                .zf("纯化后产物")
                .ph("/")
                .build());

        hscwyq2Dtos.add(SangerSjpzqTxDto.builder()
                .zf("引物3.3μM")
                .ph("/")
                .build());

        hscwyq2Dtos.add(SangerSjpzqTxDto.builder()
                .zf("H2O")
                .tj(new BigDecimal("9.75"))
                .atj(new BigDecimal("9.75").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .ph("/")
                .build());

        hscwyq2Dtos.add(SangerSjpzqTxDto.builder()
                .zf("总体积")
                .tj(new BigDecimal("20.0"))
                .atj(new BigDecimal("20.0").multiply(new BigDecimal(sampleDoubleSize + ".5")))
                .ph("/")
                .build());


        //核酸纯化一区 （测序PCR试剂配制与加样）
        SangerHschyq2 sangerHschyq2 = new SangerHschyq2();
        sangerHschyq2.setSjphjfytxdpzData(JsonUtil.toString(hscwyq2Dtos));
        sangerHschyq2.setSangerId(sangerId);

        //核酸制备区
        SangerHszbq sangerHszbq = new SangerHszbq();
        sangerHszbq.setSangerId(sangerId);
        //如果之前做过核酸提取，把一些数据同步过来
        if (Objects.nonNull(hstqId[0])) {
            ExperimentProcessSampleHstqVo experimentProcessSampleHstqVo = experimentProcessSampleHstqService.selectVoById(hstqId[0]);
            if (Objects.nonNull(experimentProcessSampleHstqVo)) {
                sangerHszbq.setLcbgwd(experimentProcessSampleHstqVo.getSyqlcbxwd());
                sangerHszbq.setSystmqj(experimentProcessSampleHstqVo.getSyqsystmqj());
                sangerHszbq.setGcywyc(experimentProcessSampleHstqVo.getHstqgcywyc());
                sangerHszbq.setClfs(experimentProcessSampleHstqVo.getHstqgcclfs());
                sangerHszbq.setZdq(experimentProcessSampleHstqVo.getZdq());
                sangerHszbq.setAqgt(experimentProcessSampleHstqVo.getSwaqg());
                sangerHszbq.setQjjzwxzssygztm(experimentProcessSampleHstqVo.getSyhqjjzwzssygztm());
                sangerHszbq.setQjyyq(experimentProcessSampleHstqVo.getSyhqjyyq());
                sangerHszbq.setQjlxj(experimentProcessSampleHstqVo.getSyhqjlxj());
                sangerHszbq.setClsyfqw(experimentProcessSampleHstqVo.getSyhclsyfqw());
            }
        }

        SangerHskzyq sangerHskzyq = new SangerHskzyq();
        sangerHskzyq.setSangerId(sangerId);


        SangerCwfxyq sangerCwfxyq = new SangerCwfxyq();
        sangerCwfxyq.setSangerId(sangerId);

        SangerHskzeq sangerHskzeq = new SangerHskzeq();
        sangerHskzeq.setSangerId(sangerId);

        SangerHscheq sangerHscheq = new SangerHscheq();
        sangerHscheq.setSangerId(sangerId);

        List<SangerCxPcrCwchSjDto> cxpcrcwchsjDataList = Lists.newArrayList();
        cxpcrcwchsjDataList.add(SangerCxPcrCwchSjDto.builder()
                .sjzl("125mM EDTA(pH=8.0)")
                .yl((new BigDecimal("2").multiply(new BigDecimal(sampleDoubleSize + ".5"))).toString())
                .build());

        cxpcrcwchsjDataList.add(SangerCxPcrCwchSjDto.builder()
                .sjzl("3M NaAc(pH=5.2))")
                .yl((new BigDecimal("2").multiply(new BigDecimal(sampleDoubleSize + ".5"))).toString())
                .build());
        sangerHscheq.setCxpcrcwchsjData(JsonUtil.toString(cxpcrcwchsjDataList));


        SangerCxq sangerCxq = new SangerCxq();
        sangerCxq.setSangerId(sangerId);

        SangerSjfx sangerSjfx = new SangerSjfx();
        sangerSjfx.setSangerId(sangerId);
        sangerSjfx.setSjfxData(JsonUtil.toString(sjfxDataList));

        //试剂配制区
        sangerSjpzqService.insert(sangerSjpzq);
        //核酸制备区
        sangerHszbqService.insert(sangerHszbq);
        //核酸扩增一区
        sangerHskzyqService.insert(sangerHskzyq);
        //产物分析一区
        sangerCwfxyqService.insert(sangerCwfxyq);
        //核酸纯化一区 （普通PCR产物纯化）
        sangerHschyq1Service.insert(sangerHschyq1);
        //核酸纯化一区 （测序PCR试剂配制与加样）
        sangerHschyq2Service.insert(sangerHschyq2);
        //核酸扩增二区 （测序PCR反应）
        sangerHskzeqService.insert(sangerHskzeq);
        //核酸纯化二区 （测序PCR产物纯化）、核酸扩增二区（变性）
        sangerHscheqService.insert(sangerHscheq);
        //测序区（毛细管电泳）
        sangerCxqService.insert(sangerCxq);
        //数据分析（测序区、分子诊断室）
        sangerSjfxService.insert(sangerSjfx);
    }

    @Override
    public boolean update(Sanger sanger) {
        Date now = new Date();
        sanger.setUpdateTime(now);
        return mapper.updateByPrimaryKey(sanger) != 0;
    }

    @Override
    public boolean update(SangerSaveOrUpdateVo sangerSaveOrUpdateVo) {
        Sanger oldSanger = this.selectById(sangerSaveOrUpdateVo.getId());
        AssertUtil.notNull(oldSanger, "此实验不存在或者已被删除");
        Sanger sanger = new Sanger();
        BeanUtils.copyProperties(sangerSaveOrUpdateVo, sanger);
        return this.updateByPrimaryKeySelective(sanger);
    }

    @Override
    public boolean updateByPrimaryKeySelective(Sanger sanger) {
        sanger.setUpdateTime(new Date());
        return mapper.updateByPrimaryKeySelective(sanger) != 0;
    }

    @Override
    public Integer count(SangerSearchVo sangerSearchVo) {
        return mapper.count(sangerSearchVo);
    }

    @Override
    public List<SangerVo> selectList(SangerSearchVo sangerSearchVo) {
        return mapper.selectList(sangerSearchVo);
    }

    @Override
    public Page<SangerVo> selectPage(SangerSearchVo sangerSearchVo) {
        //先直接查总数
        int count = count(sangerSearchVo);
        //分页
        Page<SangerVo> page = new Page<>(true, count, sangerSearchVo.getPageNum(), sangerSearchVo.getPageSize());
        sangerSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<SangerVo> responseVos = this.selectList(sangerSearchVo);
        page.setData(responseVos);
        return page;
    }

}